#include <errno.h>
#include <stdlib.h>
#include <string.h>

#include "geanyplugin.h"

GeanyPlugin     *geany_plugin;
GeanyData       *geany_data;
GeanyFunctions  *geany_functions;

PLUGIN_VERSION_CHECK(147)

PLUGIN_SET_INFO(_("Pyflakes"), _("Geany plugin integrating pyflakes"),
                "1.0.4", "Filip Gruszczyński <gruszczy@gmail.com>");

#define MARKER_FIRST								12
#define MARKER_UNDEFINED_VARIABLE                   MARKER_FIRST + 1
#define MARKER_OTHER                                MARKER_FIRST + 2

/* markers colors */
#define RGB(R,G,B)	(R | (G << 8) | (B << 16))
#define RED			    RGB(255,0,0)
#define GREEN			RGB(0,255,0)
#define BLUE			RGB(0,0,255)
#define YELLOW			RGB(255,255,0)
#define BLACK			RGB(0,0,0)
#define WHITE			RGB(255,255,255)

static void pyflakes_update_callback(GObject *, GeanyDocument *, gpointer);

static gboolean pyflakes_button_press_callback(GtkWidget *, GdkEventButton *, gpointer);

static void pyflakes_set_markers(ScintillaObject *sci);

GtkListStore *store = NULL;
GtkWidget *page = NULL;
GtkWidget *tree = NULL;

PluginCallback plugin_callbacks[] =
{
    { "document-save", (GCallback) pyflakes_update_callback, FALSE, NULL },
    { "document-activate", (GCallback) pyflakes_update_callback, TRUE, NULL },
    { "document-open", (GCallback) pyflakes_update_callback, TRUE, NULL },

	{ NULL, NULL, FALSE, NULL }
};

void plugin_init(GeanyData *data)
{   
    GtkCellRenderer *text_renderer;
	GtkTreeViewColumn *column;
        
    page = gtk_scrolled_window_new(NULL, NULL);
	store = gtk_list_store_new(2, G_TYPE_INT, G_TYPE_STRING);
	tree = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(page),
		GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
    g_signal_connect(tree, "button-press-event", 
                     G_CALLBACK(pyflakes_button_press_callback), NULL);

	text_renderer = gtk_cell_renderer_text_new();
	column = gtk_tree_view_column_new();
	gtk_tree_view_column_set_title(column, _("Line"));
	gtk_tree_view_column_pack_start(column, text_renderer, TRUE);
	gtk_tree_view_column_set_attributes(column, text_renderer, "text",
		0, NULL);
	gtk_tree_view_column_set_sort_indicator(column, FALSE);
	gtk_tree_view_column_set_sort_column_id(column, 0);
	gtk_tree_view_column_set_resizable(column, TRUE);
	gtk_tree_view_append_column(GTK_TREE_VIEW(tree), column);

	text_renderer = gtk_cell_renderer_text_new();
	column = gtk_tree_view_column_new();
	gtk_tree_view_column_set_title(column, _("Error"));
	gtk_tree_view_column_pack_start(column, text_renderer, TRUE);
	gtk_tree_view_column_set_attributes(column, text_renderer, "text",
		1, NULL);
	gtk_tree_view_column_set_sort_indicator(column, FALSE);
	gtk_tree_view_column_set_sort_column_id(column, 1);
	gtk_tree_view_column_set_resizable(column, TRUE);
	gtk_tree_view_append_column(GTK_TREE_VIEW(tree), column);

	gtk_container_add(GTK_CONTAINER(page), tree);
	gtk_widget_show_all(page);
            
	gtk_notebook_append_page(GTK_NOTEBOOK(ui_lookup_widget(geany->main_widgets->window, 
                                                           "notebook_info")),
                             page, gtk_label_new(_("Pyflakes")));
}

void plugin_cleanup(void)
{
    gtk_widget_destroy(page);
    gtk_widget_destroy(tree);
}

static int pyflakes_get_line(gchar *str)
{
    gchar *start = strchr(str, ':');

    if (start){
        start++;
        errno = 0;
        unsigned int result = strtoul(start, NULL, 10);
        if (errno)
            return -1;
        return (int) result;
    }
    return -1;
}

static void pyflakes_clear_markers(ScintillaObject *sci){
    int lines = sci_get_line_count(sci);
    int i = 0;
    for (i = 0; i < lines; ++i) {
        sci_delete_marker_at_line(sci, i, MARKER_UNDEFINED_VARIABLE);
        sci_delete_marker_at_line(sci, i, MARKER_OTHER);
    }
};

static void show_output(gchar *str, GeanyDocument *doc)
{
    if (!store)
        return;
        
    gchar **split = g_strsplit(str, "\n", 0);
    gchar **pointer = NULL;

    gtk_list_store_clear(store);
    for (pointer = split; *pointer; pointer++)
        if (strlen(*pointer)){
            int line = pyflakes_get_line(*pointer);
            if (line != -1){
                if (line > 0)
                    line = line - 1;
                else
                    line = 0;
                if (strstr(*pointer, "undefined name"))
                    sci_set_marker_at_line(doc->editor->sci, line, MARKER_UNDEFINED_VARIABLE);
                else
                    sci_set_marker_at_line(doc->editor->sci, line, MARKER_OTHER);
                editor_indicator_set_on_line(doc->editor, GEANY_INDICATOR_ERROR, line);
                gtk_list_store_insert_with_values(store, NULL, -1, 0, line, 1, *pointer, -1);
            }
        }
    g_strfreev(split);
}

static gboolean pyflakes_selection_changed_callback(gpointer data)
{
	GtkTreeIter iter;
	GtkTreeModel *model;
    GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree));
    int line = 0;
    GeanyDocument *doc = document_get_current();
    
    if (gtk_tree_selection_get_selected(selection, &model, &iter)){
        gtk_tree_model_get(model, &iter, 0, &line, -1);
        sci_goto_line(doc->editor->sci, line - 1, TRUE);
        gtk_widget_grab_focus(GTK_WIDGET(doc->editor->sci));
    }

    return FALSE;
}

static gboolean pyflakes_button_press_callback(GtkWidget *widget, GdkEventButton *event, gpointer data)
{
	if (event->button == 1)
	{	/* allow reclicking of a treeview item */
		g_idle_add(pyflakes_selection_changed_callback, data);
	}
    return FALSE;
}

static void pyflakes_update_callback(GObject *obj, GeanyDocument *doc, 
                                     gpointer user_data)
{
    gchar *output = NULL;
    gchar *error = NULL;
    gint *status = NULL;
    gchar *args[4];
    args[0] = "pyflakes";
    args[1] = doc->real_path;
    args[2] = (gchar *) NULL;
    
    if (!doc->file_name)
        return;
    
    gchar *extension = strrchr(doc->file_name, '.');
    if (!extension || strcmp(extension, ".py")) {
        gtk_list_store_clear(store);
        return;
    }
    
    pyflakes_set_markers(doc->editor->sci);
    if (!utils_spawn_sync(NULL, args, NULL, 
                          G_SPAWN_LEAVE_DESCRIPTORS_OPEN | G_SPAWN_SEARCH_PATH, 
                          (GSpawnChildSetupFunc) NULL, (gpointer) NULL,
                          &output, &error, status, NULL))
        return;
    editor_indicator_clear(doc->editor, GEANY_INDICATOR_ERROR);        
    pyflakes_clear_markers(doc->editor->sci);
    if (output && strlen(output))
        show_output(output, doc);
    else
        gtk_list_store_clear(store);
    g_free(output);
    g_free(error);

}

static void pyflakes_set_markers(ScintillaObject *sci) 
{
	scintilla_send_message(sci, SCI_MARKERDEFINE, MARKER_UNDEFINED_VARIABLE, SC_MARK_ARROW);
	scintilla_send_message(sci, SCI_MARKERSETFORE, MARKER_UNDEFINED_VARIABLE, RED);

	scintilla_send_message(sci, SCI_MARKERDEFINE, MARKER_OTHER, SC_MARK_ARROW);
	scintilla_send_message(sci, SCI_MARKERSETFORE, MARKER_OTHER, YELLOW);
}
